package com.kye.express.business.common_tool_new;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.util.Pair;

import com.kye.base.Logger;
import com.kye.base.utils.GsonUtils;
import com.kye.express.App;
import com.kye.express.R;
import com.kye.express.business.common_tool_new.viewmodel.CommonToolEditModel;
import com.kye.express.business.common_tool_new.viewmodel.CommonToolNormalModel;
import com.kye.express.contract.base.BasePresenter;
import com.kye.express.contract.base.view.IView;
import com.kye.model.AppDatabase;
import com.kye.model.bean.common_tool.CommonToolItemBean;
import com.kye.model.dao.CommonToolDao;

import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import io.reactivex.BackpressureStrategy;
import io.reactivex.Flowable;
import io.reactivex.FlowableEmitter;
import io.reactivex.FlowableOnSubscribe;
import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.Single;
import io.reactivex.SingleEmitter;
import io.reactivex.SingleObserver;
import io.reactivex.SingleOnSubscribe;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.BiFunction;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.functions.Predicate;
import io.reactivex.schedulers.Schedulers;
import me.drakeet.multitype.MultiTypeAdapter;

public interface CommonToolContract {

    interface CommonToolView extends IView {

        void showPageEmpty();

        void showPageContent();

        void showPageEdit();

        void updateNormalSelectedCommonTools(List<CommonToolNormalModel> commonToolNormalModels);

        void updateEditSelectedCommonTools(List<CommonToolEditModel> commonToolEditModels);

        void updateEditUnselectedCommonTools(List<CommonToolEditModel> commonToolEditModels);

        MultiTypeAdapter getSelectedNormalAdapter();

        MultiTypeAdapter getSelectedEditAdapter();

        MultiTypeAdapter getUnselectedEditAdapter();
    }

    class CommonToolPresenter extends BasePresenter<CommonToolView> {

        private final static String TAG_IS_FIRST_INIT = "TAG_IS_FIRST_INIT";
        private final static String TAG_COMMON_SELECTED_TOOLS_NORMAL = "TAG_COMMON_SELECTED_TOOLS_NORMAL";
        private final static String TAG_COMMON_SELECTED_TOOLS_EDIT = "TAG_COMMON_SELECTED_TOOLS_EDIT";
        private final static String TAG_COMMON_UNSELECTED_TOOLS_EDIT = "TAG_COMMON_UNSELECTED_TOOLS_EDIT";
        private ArrayList<CommonToolNormalModel> selectedCommonToolsNormal = new ArrayList<>();
        private ArrayList<CommonToolEditModel> selectedCommonToolsEdit = new ArrayList<>();
        private ArrayList<CommonToolEditModel> unselectedCommonToolsEdit = new ArrayList<>();

        private CommonToolDao commonToolDao;

        @Override
        public void bind(CommonToolView view) {
            super.bind(view);
        }

        @Override
        public void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            commonToolDao = AppDatabase.getInstance(App.getContext().getApplicationContext())
                    .commonToolDao();
            if (savedInstanceState != null) {
                selectedCommonToolsNormal = savedInstanceState.getParcelableArrayList(TAG_COMMON_SELECTED_TOOLS_NORMAL);
                selectedCommonToolsEdit = savedInstanceState.getParcelableArrayList(TAG_COMMON_SELECTED_TOOLS_EDIT);
                unselectedCommonToolsEdit = savedInstanceState.getParcelableArrayList(TAG_COMMON_UNSELECTED_TOOLS_EDIT);
            }
        }

        @Override
        public void onSaveInstanceState(Bundle outState) {
            super.onSaveInstanceState(outState);
            outState.putParcelableArrayList(TAG_COMMON_SELECTED_TOOLS_NORMAL, selectedCommonToolsNormal);
            outState.putParcelableArrayList(TAG_COMMON_SELECTED_TOOLS_EDIT, selectedCommonToolsEdit);
            outState.putParcelableArrayList(TAG_COMMON_UNSELECTED_TOOLS_EDIT, unselectedCommonToolsEdit);
        }

        /**
         * 获取默认常用工具数据，xml配置
         *
         * @return
         */
        public Single<List<CommonToolItemBean>> getInitCommonData() {
            return
                    Flowable
                            .create(new FlowableOnSubscribe<Pair<List<String>, List<Integer>>>() {
                                @Override
                                public void subscribe(FlowableEmitter<Pair<List<String>, List<Integer>>> e) throws Exception {
                                    List<String> commonToolNames = Arrays.asList(App.getInstance().getResources().getStringArray(R.array.common_tool_items_names));
                                    int[] commonToolIdsArray = App.getInstance().getResources().getIntArray(R.array.common_tool_items_ids);
                                    List<Integer> commonToolIds = new ArrayList<>();
                                    for (int id : commonToolIdsArray) {
                                        commonToolIds.add(id);
                                    }
                                    e.onNext(new Pair<List<String>, List<Integer>>(commonToolNames, commonToolIds));
                                    e.onComplete();
                                }
                            }, BackpressureStrategy.DROP)
                            .flatMap(new Function<Pair<List<String>, List<Integer>>, Flowable<CommonToolItemBean>>() {
                                @Override
                                public Flowable<CommonToolItemBean> apply(Pair<List<String>, List<Integer>> listListPair) throws Exception {
                                    Flowable<String> nameFlowable = Flowable.fromIterable(listListPair.first);
                                    Flowable<Integer> idsFlowable = Flowable.fromIterable(listListPair.second);
                                    Flowable<CommonToolItemBean> zip = Flowable.zip(nameFlowable, idsFlowable, new BiFunction<String, Integer, CommonToolItemBean>() {
                                        @Override
                                        public CommonToolItemBean apply(String name, Integer id) throws Exception {
                                            return new CommonToolItemBean(id, name, false, id - 1, 0, id - 1);
                                        }
                                    });
                                    return zip;
                                }
                            })
                            .toList();
        }

        /**
         * 首次查询数据库
         *
         * @return
         */
        public Single<List<CommonToolItemBean>> getInitCommonDataDB() {
            return
                    Single.create(new SingleOnSubscribe<List<CommonToolItemBean>>() {
                        @Override
                        public void subscribe(SingleEmitter<List<CommonToolItemBean>> e) throws Exception {
                            try {
                                List<CommonToolItemBean> commonToolItemBeans = AppDatabase.getInstance(App.getContext())
                                        .commonToolDao().queryAll();
                                if (commonToolItemBeans == null) {
                                    commonToolItemBeans = new ArrayList<>();
                                }
                                e.onSuccess(commonToolItemBeans);
                            } catch (Throwable throwable) {
                                e.onError(throwable);
                            }
                        }
                    });
        }

        /**
         * 初始化数据
         */
        public void initCommonToolsData() {
            Single<List<CommonToolItemBean>> initCommonDataDefault = getInitCommonData();
            Single<List<CommonToolItemBean>> initCommonDataDB = getInitCommonDataDB();
            Observable.zip(initCommonDataDB.toObservable(), initCommonDataDefault.toObservable(), new BiFunction<List<CommonToolItemBean>, List<CommonToolItemBean>, List<CommonToolItemBean>>() {
                @Override
                public List<CommonToolItemBean> apply(List<CommonToolItemBean> commonToolItemDb, List<CommonToolItemBean> commonToolItemInit) throws Exception {
                    if (commonToolItemDb == null || commonToolItemDb.size() <= 0) {
//                            Logger.d("use init data");
                        commonToolDao.insert(commonToolItemInit);
                        return commonToolItemInit;
                    } else {
//                            Logger.d("use db data");
                        return commonToolItemDb;
                    }
                }
            })
                    .flatMap(new Function<List<CommonToolItemBean>, ObservableSource<CommonToolItemBean>>() {
                        @Override
                        public ObservableSource<CommonToolItemBean> apply(List<CommonToolItemBean> commonToolItemBeans) throws Exception {
                            return Observable.fromIterable(commonToolItemBeans);
                        }
                    })
                    .filter(new Predicate<CommonToolItemBean>() {
                        @Override
                        public boolean test(CommonToolItemBean commonToolItemBean) throws Exception {
                            return commonToolItemBean.isSelected();
                        }
                    })
                    .toList()
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new SingleObserver<List<CommonToolItemBean>>() {
                        @Override
                        public void onSubscribe(Disposable d) {
                            addDisposable(d);
                        }

                        @Override
                        public void onSuccess(List<CommonToolItemBean> commonToolItemBeans) {
                            Logger.d("onSuccess : \n" + GsonUtils.toJsonString(commonToolItemBeans, true));
                            if (commonToolItemBeans.size() <= 0) {
                                // 没有任何选中的数据
                                getView().showPageEmpty();
                            } else {
                                // 之前选中数据
                                getView().showPageContent();
                            }
                            bindNormalSelectedCommonTool();
                            bindEditSelectedCommonTool();
                            bindEditUnselectedCommonTool();
                        }

                        @Override
                        public void onError(Throwable e) {
                            Logger.d("onError : " + e.getMessage());
                        }
                    });

        }

        public void refreshStatusPage() {
            Single<List<CommonToolItemBean>> initCommonDataDefault = getInitCommonData();
            Single<List<CommonToolItemBean>> initCommonDataDB = getInitCommonDataDB();
            Observable.zip(initCommonDataDB.toObservable(), initCommonDataDefault.toObservable(), new BiFunction<List<CommonToolItemBean>, List<CommonToolItemBean>, List<CommonToolItemBean>>() {
                @Override
                public List<CommonToolItemBean> apply(List<CommonToolItemBean> commonToolItemDb, List<CommonToolItemBean> commonToolItemInit) throws Exception {
                    if (commonToolItemDb == null || commonToolItemDb.size() <= 0) {
//                            Logger.d("use init data");
                        commonToolDao.insert(commonToolItemInit);
                        return commonToolItemInit;
                    } else {
//                            Logger.d("use db data");
                        return commonToolItemDb;
                    }
                }
            })
                    .flatMap(new Function<List<CommonToolItemBean>, ObservableSource<CommonToolItemBean>>() {
                        @Override
                        public ObservableSource<CommonToolItemBean> apply(List<CommonToolItemBean> commonToolItemBeans) throws Exception {
                            return Observable.fromIterable(commonToolItemBeans);
                        }
                    })
                    .filter(new Predicate<CommonToolItemBean>() {
                        @Override
                        public boolean test(CommonToolItemBean commonToolItemBean) throws Exception {
                            return commonToolItemBean.isSelected();
                        }
                    })
                    .toList()
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new SingleObserver<List<CommonToolItemBean>>() {
                        @Override
                        public void onSubscribe(Disposable d) {
                            addDisposable(d);
                        }

                        @Override
                        public void onSuccess(List<CommonToolItemBean> commonToolItemBeans) {
                            Logger.d("onSuccess : \n" + GsonUtils.toJsonString(commonToolItemBeans, true));
                            if (commonToolItemBeans.size() <= 0) {
                                // 没有任何选中的数据
                                getView().showPageEmpty();
                            } else {
                                // 之前选中数据
                                getView().showPageContent();
                            }
                        }

                        @Override
                        public void onError(Throwable e) {
                            Logger.d("onError : " + e.getMessage());
                        }
                    });
        }

        /**
         * 绑定监听内容界面选中数据
         */
        public void bindNormalSelectedCommonTool() {
            commonToolDao.querySelectedFlowable()
                    .compose(getView().<List<CommonToolItemBean>>bindToLifecycleDestroy())
                    .map(new Function<List<CommonToolItemBean>, List<CommonToolItemBean>>() {
                        @Override
                        public List<CommonToolItemBean> apply(List<CommonToolItemBean> commonToolItemBeans) throws Exception {
                            Collections.sort(commonToolItemBeans, new Comparator<CommonToolItemBean>() {
                                @Override
                                public int compare(CommonToolItemBean o1, CommonToolItemBean o2) {
                                    return o1.getPositionSelected() - o2.getPositionSelected();
                                }
                            });
                            return commonToolItemBeans;
                        }
                    })
                    .map(new Function<List<CommonToolItemBean>, List<CommonToolNormalModel>>() {
                        @Override
                        public List<CommonToolNormalModel> apply(List<CommonToolItemBean> commonToolItemBeans) throws Exception {
                            List<CommonToolNormalModel> commonToolNormalModels = new ArrayList<>();
                            for (int i = 0; i < commonToolItemBeans.size(); i++) {
                                CommonToolNormalModel commonToolNormalModel = CommonToolNormalModel.createFromCommonToolItemBean(commonToolItemBeans.get(i));
                                commonToolNormalModels.add(commonToolNormalModel);
                            }
                            return commonToolNormalModels;
                        }
                    })
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new Subscriber<List<CommonToolNormalModel>>() {
                        @Override
                        public void onSubscribe(Subscription s) {
                            s.request(Integer.MAX_VALUE);
                        }

                        @Override
                        public void onNext(List<CommonToolNormalModel> commonToolNormalModels) {
                            Logger.d("1 : bindNormalSelectedCommonTool\n" + GsonUtils.toJsonString(commonToolNormalModels, true));
                            selectedCommonToolsNormal = (ArrayList<CommonToolNormalModel>) commonToolNormalModels;
                            getView().updateNormalSelectedCommonTools(commonToolNormalModels);
                        }

                        @Override
                        public void onError(Throwable t) {
                            Logger.d("1 : onError\n" + t.getMessage());
                        }

                        @Override
                        public void onComplete() {

                        }
                    });
        }

        /**
         * 绑定监听编辑界面选中数据
         */
        public void bindEditSelectedCommonTool() {
            commonToolDao.querySelectedFlowable()
                    .compose(getView().<List<CommonToolItemBean>>bindToLifecycleDestroy())
                    .map(new Function<List<CommonToolItemBean>, List<CommonToolItemBean>>() {
                        @Override
                        public List<CommonToolItemBean> apply(List<CommonToolItemBean> commonToolItemBeans) throws Exception {
                            Collections.sort(commonToolItemBeans, new Comparator<CommonToolItemBean>() {
                                @Override
                                public int compare(CommonToolItemBean o1, CommonToolItemBean o2) {
                                    return o1.getPositionSelected() - o2.getPositionSelected();
                                }
                            });
                            return commonToolItemBeans;
                        }
                    })
                    .map(new Function<List<CommonToolItemBean>, List<CommonToolEditModel>>() {
                        @Override
                        public List<CommonToolEditModel> apply(List<CommonToolItemBean> commonToolItemBeans) throws Exception {
                            List<CommonToolEditModel> commonToolEditModels = new ArrayList<>();
                            for (int i = 0; i < commonToolItemBeans.size(); i++) {
                                CommonToolEditModel commonToolEditModel = CommonToolEditModel.createFromCommonToolItemBean(commonToolItemBeans.get(i));
                                commonToolEditModels.add(commonToolEditModel);
                            }
                            return commonToolEditModels;
                        }
                    })
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new Subscriber<List<CommonToolEditModel>>() {
                        @Override
                        public void onSubscribe(Subscription s) {
                            s.request(Integer.MAX_VALUE);
                        }

                        @Override
                        public void onNext(List<CommonToolEditModel> commonToolEditModels) {
                            Logger.d("2 - selected : bindEditSelectedCommonTool\n" + GsonUtils.toJsonString(commonToolEditModels, true));
                            selectedCommonToolsEdit = (ArrayList<CommonToolEditModel>) commonToolEditModels;
                            getView().updateEditSelectedCommonTools(commonToolEditModels);
                        }

                        @Override
                        public void onError(Throwable t) {
                            Logger.d("2 - selected : onError\n" + t.getMessage());
                        }

                        @Override
                        public void onComplete() {

                        }
                    });
        }

        /**
         * 绑定监听编辑界面未选中数据
         */
        public void bindEditUnselectedCommonTool() {
            commonToolDao.queryUnselectedFlowable()
                    .compose(getView().<List<CommonToolItemBean>>bindToLifecycleDestroy())
                    .map(new Function<List<CommonToolItemBean>, List<CommonToolItemBean>>() {
                        @Override
                        public List<CommonToolItemBean> apply(List<CommonToolItemBean> commonToolItemBeans) throws Exception {
                            Collections.sort(commonToolItemBeans, new Comparator<CommonToolItemBean>() {
                                @Override
                                public int compare(CommonToolItemBean o1, CommonToolItemBean o2) {
                                    return o1.getPosition() - o2.getPosition();
                                }
                            });
                            return commonToolItemBeans;
                        }
                    })
                    .map(new Function<List<CommonToolItemBean>, List<CommonToolEditModel>>() {
                        @Override
                        public List<CommonToolEditModel> apply(List<CommonToolItemBean> commonToolItemBeans) throws Exception {
                            List<CommonToolEditModel> commonToolEditModels = new ArrayList<>();
                            for (int i = 0; i < commonToolItemBeans.size(); i++) {
                                CommonToolEditModel commonToolEditModel = CommonToolEditModel.createFromCommonToolItemBean(commonToolItemBeans.get(i));
                                commonToolEditModels.add(commonToolEditModel);
                            }
                            return commonToolEditModels;
                        }
                    })
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new Subscriber<List<CommonToolEditModel>>() {
                        @Override
                        public void onSubscribe(Subscription s) {
                            s.request(Integer.MAX_VALUE);
                        }

                        @Override
                        public void onNext(List<CommonToolEditModel> commonToolEditModels) {
                            Logger.d("2 - unselected : bindEditSelectedCommonTool\n" + GsonUtils.toJsonString(commonToolEditModels, true));
                            unselectedCommonToolsEdit = (ArrayList<CommonToolEditModel>) commonToolEditModels;
                            getView().updateEditUnselectedCommonTools(commonToolEditModels);
                        }

                        @Override
                        public void onError(Throwable t) {
                            Logger.d("2 - unselected : onError\n" + t.getMessage());
                        }

                        @Override
                        public void onComplete() {

                        }
                    });
        }

        public void updateCommonToolsData() {
            Observable<CommonToolItemBean> editSelected = Observable.fromIterable(selectedCommonToolsEdit)
                    .map(new Function<CommonToolEditModel, CommonToolItemBean>() {
                        @Override
                        public CommonToolItemBean apply(CommonToolEditModel commonToolEditModel) throws Exception {
                            return CommonToolEditModel.createToCommonToolItemBean(commonToolEditModel);
                        }
                    })
                    .doOnNext(new Consumer<CommonToolItemBean>() {
                        @Override
                        public void accept(CommonToolItemBean commonToolItemBean) throws Exception {
                            commonToolItemBean.setPositionSelected(selectedCommonToolsEdit.indexOf(commonToolItemBean));
                        }
                    });
            Observable<CommonToolItemBean> editUnselected = Observable.fromIterable(unselectedCommonToolsEdit)
                    .map(new Function<CommonToolEditModel, CommonToolItemBean>() {
                        @Override
                        public CommonToolItemBean apply(CommonToolEditModel commonToolEditModel) throws Exception {
                            return CommonToolEditModel.createToCommonToolItemBean(commonToolEditModel);
                        }
                    });
            Observable.concat(editSelected, editUnselected)
                    .toList()
                    .map(new Function<List<CommonToolItemBean>, List<Long>>() {
                        @Override
                        public List<Long> apply(List<CommonToolItemBean> commonToolItemBeans) throws Exception {
                            return commonToolDao.insertAll(commonToolItemBeans);
                        }
                    })
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new SingleObserver<List<Long>>() {
                        @Override
                        public void onSubscribe(Disposable d) {

                        }

                        @Override
                        public void onSuccess(List<Long> longs) {
                            Logger.d("insertAll : \n" + GsonUtils.toJsonString(longs, true));
                            refreshStatusPage();
                        }

                        @Override
                        public void onError(Throwable e) {

                        }
                    });
            Logger.d("1   selected ===> :\n" + GsonUtils.toJsonString(selectedCommonToolsEdit, true));
            Logger.d("2 unselected ===> :\n" + GsonUtils.toJsonString(unselectedCommonToolsEdit, true));
        }

        public void removeSelected(CommonToolEditModel fromSelected) {
            fromSelected.setSelected(false);
            int removePosition = selectedCommonToolsEdit.indexOf(fromSelected);
            int addPosition = unselectedCommonToolsEdit.size();
            selectedCommonToolsEdit.remove(fromSelected);
            unselectedCommonToolsEdit.add(fromSelected);
            getView().getSelectedEditAdapter().notifyItemRemoved(removePosition);
            getView().getUnselectedEditAdapter().notifyItemInserted(addPosition);
        }

        public void addSelected(CommonToolEditModel fromUnselected) {
            fromUnselected.setSelected(true);
            int removePosition = unselectedCommonToolsEdit.indexOf(fromUnselected);
            int addPosition = selectedCommonToolsEdit.size();
            selectedCommonToolsEdit.add(fromUnselected);
            unselectedCommonToolsEdit.remove(fromUnselected);
            getView().getSelectedEditAdapter().notifyItemInserted(addPosition);
            getView().getUnselectedEditAdapter().notifyItemRemoved(removePosition);
        }
    }
}
